package myServer.session;

import component.userInformation.UserAttribute;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.Data;

import java.util.UUID;

@Data
public class ServerSession {

    public static final AttributeKey<String> KEY_USER_ID = AttributeKey.valueOf("KEY_USER_ID");
    public static final AttributeKey<ServerSession> SESSION_KEY = AttributeKey.valueOf("SESSION_KEY");
    private final String serverSessionID;  // ServerSession唯一标识
    private Channel channel;  // channel
    private UserAttribute userAttribute;  //用户基本信息
    private boolean isLogin = false; // 用户是否登录

    /**
     * 将 channel绑定到 ServerSession
     */
    public ServerSession(Channel channel) {
        //将 Channel绑定到 ServerSession
        this.channel = channel;
        // UUID保证 ServerSession ID唯一
        this.serverSessionID = UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 通过 Channel获取 ServerSession
     */
    public static ServerSession getSessionByCtx(ChannelHandlerContext context) {
        return context.channel()
                .attr(ServerSession.SESSION_KEY)
                .get();
    }

    /**
     * 关闭 Channel
     */
    public static void closeChannelBySession(ChannelHandlerContext context) {
        ServerSession session = getSessionByCtx(context);
        if (session != null && session.getUserAttribute() != null) {
            session.close();
            SessionMap.instance().removeSession(session.getServerSessionID());
        }
    }

    /**
     * <ol>
     *     <li>将 ServerSession绑定到 Channel</li>
     *     <li>将 Session添加到 SessionMap</li>
     * </ol>
     */
    public void bindChannelWithServerSession() {
        System.out.println("ServerSession 绑定会话 " + channel.remoteAddress());
        //将 ServerSession绑定到 Channel
        channel.attr(ServerSession.SESSION_KEY).set(this);
        SessionMap.instance().addSession(this);
        isLogin = true;
    }

    /**
     * 解除绑定，将 ServerSession从 SessionMap中删除
     */
    public ServerSession unbind() {
        isLogin = false;
        SessionMap.instance().removeSession(this.getServerSessionID());
        this.close();
        return this;
    }

    /**
     * 关闭 channel
     */
    public synchronized void close() {
        ChannelFuture future = channel.close();
        future.addListener((ChannelFutureListener) future1 -> {
            if (!future.isSuccess()) {
                System.out.println("关闭 channel 失败");
            }
        });
    }

    /**
     * 将信息写入 channel并 flush
     */
    public synchronized void writeAndFlush(Object message) {
        //当系统水位过高时，系统应该暂缓发送信息，防止发送队列积压
        if (channel.isWritable()) {  //低水位
            channel.writeAndFlush(message);
        } else {    //高水位
            System.out.println("channel 繁忙,信息被暂存...");
            //写入信息暂存的分布式存储，如：MongoDB
            //等 channel空闲之后，再 writeAndFlush
        }
    }

}
